#!/usr/bin/env bash

# --- Configuration ---
export KUBECONFIG=/etc/kubernetes/admin.conf
API_SERVER_PORT="6443"
CRI_SOCKET="unix:///var/run/cri-dockerd.sock"
# CRI_SOCKET="unix:///run/containerd/containerd.sock"
# CRI_SOCKET="unix:///var/run/crio/crio.sock"

# --- Sanity Checks ---
if [ "$(id -u)" -ne 0 ]; then echo "ERROR: 此脚本需要以 root 用户权限运行。" >&2; exit 10; fi
if [ ! -f "$KUBECONFIG" ]; then echo "ERROR: KUBECONFIG 文件 '$KUBECONFIG' 不存在或无法访问。" >&2; exit 11; fi
if ! command -v kubeadm &> /dev/null; then echo "ERROR: 'kubeadm' 命令未找到。" >&2; exit 12; fi
if ! command -v openssl &> /dev/null; then echo "ERROR: 'openssl' 命令未找到。" >&2; exit 13; fi
if ! date -d "now" &>/dev/null; then echo "ERROR: 'date' 命令不支持 '-d' 选项 (需要 GNU date)。" >&2; exit 14; fi
if ! command -v awk &> /dev/null; then echo "ERROR: 'awk' 命令未找到。" >&2; exit 15; fi

###############################################################################
# 函数定义区
###############################################################################

# --- Cleanup function ---
cleanup() {
  :
}
trap cleanup EXIT INT TERM

# 获取Master节点IP (保持不变)
get_master_ip() {
    local master_ip=""
    # ... (内容同前) ...
    if [ -f "/etc/kubernetes/manifests/kube-apiserver.yaml" ]; then
        master_ip=$(grep -Eo '(--advertise-address=([0-9]{1,3}\.){3}[0-9]{1,3})' /etc/kubernetes/manifests/kube-apiserver.yaml | cut -d= -f2 | head -n 1)
    fi
    if [ -z "$master_ip" ] || ! [[ "$master_ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
        master_ip=$(grep 'server:' "$KUBECONFIG" | awk '{print $2}' | sed -e 's#https://##' -e 's#:.*##')
    fi
    if ! [[ "$master_ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
        echo "ERROR: 无法自动获取有效的 Master IP 地址。" >&2
        exit 1
    fi
    echo "$master_ip"
}

# 删除过期的Token (使用用户提供的函数逻辑, 增加 stderr 输出和 trap)
delete_expired_tokens() {
    local tmp_file=$(mktemp /tmp/kubeadm_del_tokens.XXXXXX)
    # 函数退出时清理临时文件
    trap "rm -f '$tmp_file'" RETURN

    # 移除 2>/dev/null 以便调试
    if ! kubeadm token list > "$tmp_file"; then
        echo "ERROR: delete_expired_tokens: 无法获取 Token 列表，请检查权限或集群状态。" >&2
        # 不退出脚本，尽力而为
        return 1
    fi

    local deleted=0
    local current_ts=$(date -u +%s)

    # 使用用户提供的循环和过滤逻辑
    while IFS= read -r line; do
        [ -z "$line" ] && continue
        # 注意：默认输出中 DESCRIPTION 是第 5 列或更后，取决于 token 类型
        # 用户提供的 grep 检查整行，可能更符合原始意图
        if echo "$line" | grep -q "kubeadm init" && echo "$line" | grep -q "generated by"; then
            local token=$(echo "$line" | awk '{print $1}')
            local expires=$(echo "$line" | awk '{print $3}')

            if [ "$token" = "TOKEN" ]; then continue; fi # 跳过表头

            # 跳过永不过期
            if [[ "$expires" == "<never>" || "$expires" == "<unknown>" ]]; then continue; fi

            local expires_ts
            expires_ts=$(date -d "$expires" -u +%s 2>/dev/null)

            if [ -n "$expires_ts" ] && [ "$expires_ts" -le "$current_ts" ]; then
                echo "[INFO] (delete_expired_tokens) 正在删除匹配条件的过期 Token: $token" >&2 # 输出到 stderr
                if kubeadm token delete "$token"; then
                    deleted=$((deleted+1))
                else
                     echo "[WARNING] (delete_expired_tokens) 删除 Token '$token' 失败。" >&2
                fi
            fi
        fi
    done < "$tmp_file"
    # trap 会清理 tmp_file
    return 0 # 表示尝试完成
}

# 查找有效的Token (使用用户提供的函数逻辑, 增加 stderr 输出和 trap)
find_valid_token() {
    local tmp_file=$(mktemp /tmp/kubeadm_find_tokens.XXXXXX)
    trap "rm -f '$tmp_file'" RETURN

    # 移除 2>/dev/null 以便调试
    # 使用 sort -k3r 按过期时间排序，最新的在前
    if ! kubeadm token list | sort -k3r > "$tmp_file"; then
        echo "ERROR: find_valid_token: 无法获取或排序 Token 列表。" >&2
        # 在失败时输出空字符串，符合函数的信号机制
        echo ""
        return 1 # 返回非0表示获取失败
    fi

    local found_token=""
    local current_ts=$(date -u +%s)

    # 使用用户提供的循环和过滤逻辑
    while IFS= read -r line; do
        [ -z "$line" ] && continue
        if [ "$(echo "$line" | awk '{print $1}')" = "TOKEN" ]; then continue; fi # 跳过表头

        # 使用 grep 检查整行
        if echo "$line" | grep -q "kubeadm init" && echo "$line" | grep -q "generated by"; then
            local token=$(echo "$line" | awk '{print $1}')
            local expires=$(echo "$line" | awk '{print $3}')

            if [[ "$expires" == "<never>" ]]; then
                 found_token="$token"
                 break # 优先使用永不过期的
            fi

            local expires_ts
            expires_ts=$(date -d "$expires" -u +%s 2>/dev/null)

            if [ -n "$expires_ts" ] && [ "$expires_ts" -gt "$current_ts" ]; then
                found_token="$token"
                break # 找到第一个未过期的就停止
            fi
        fi
    done < "$tmp_file"

    # 输出找到的 token (如果没找到就是空字符串) 到 stdout
    echo "$found_token"

    # trap 会清理 tmp_file

    # 根据是否找到 token 返回退出码 (可选，主要依赖 echo 输出)
    if [ -n "$found_token" ]; then
        return 0 # 成功找到
    else
        return 1 # 未找到 (但仍然 echo "" 了)
    fi
}


# 生成新的 Bootstrap Token (保持不变)
generate_new_token() {
    local new_token_line
    echo "[INFO] 正在生成新的 bootstrap token (默认有效期 24 小时)..." >&2

    if ! new_token_line=$(kubeadm token create --print-join-command --ttl 24h --description "生成24小时引导令牌,"); then
        echo "ERROR: 生成新 Token 失败 (kubeadm token create)。" >&2
        return 1
    fi

    if [[ "$new_token_line" =~ --token[[:space:]]+([a-z0-9]{6}\.[a-z0-9]{16}) ]]; then
        echo "${BASH_REMATCH[1]}" # Output token to stdout
        return 0
    else
        echo "ERROR: 无法从 'kubeadm token create --print-join-command' 的输出中解析 Token。" >&2
        echo "输出内容: $new_token_line" >&2
        return 1
    fi
}

# 获取CA证书哈希值 (保持不变)
get_ca_hash() {
    local ca_cert_path="/etc/kubernetes/pki/ca.crt"
    if [ ! -f "$ca_cert_path" ]; then echo "ERROR: CA 证书 '$ca_cert_path' 不存在。" >&2; exit 5; fi
    local ca_hash
    ca_hash=$(openssl x509 -pubkey -in "$ca_cert_path" | openssl pkey -pubin -outform der | openssl dgst -sha256 -hex | sed 's/^.* //')
    if [ -z "$ca_hash" ]; then echo "ERROR: 无法计算 CA 哈希。" >&2; exit 3; fi
    echo "sha256:$ca_hash"
}

# 上传证书并获取 Certificate Key (保持不变)
get_certificate_key() {
    local upload_output certificate_key
    echo "[INFO] 正在上传控制平面证书并生成临时加密密钥 (有效期 2 小时)..." >&2

    upload_output=$(kubeadm init phase upload-certs --upload-certs 2>&1)
    local exit_code=$?
    if [ $exit_code -ne 0 ]; then
        echo "ERROR: 执行 'upload-certs' 失败。" >&2; echo "错误输出: $upload_output" >&2; return 1;
    fi

    certificate_key=$(echo "$upload_output" | grep -Eo '[a-f0-9]{64}' | tail -n 1)
    if [[ "$certificate_key" =~ ^[a-f0-9]{64}$ ]]; then
        echo "$certificate_key"
        return 0
    else
        echo "ERROR: 未能从 'upload-certs' 输出中提取有效 key。" >&2; echo "命令输出: $upload_output" >&2; return 1;
    fi
}


# 生成 Worker 节点 Join 命令 (保持不变)
generate_worker_join_command() {
    local master_ip_port="$1" token="$2" ca_hash="$3"
    echo "kubeadm join ${master_ip_port} --token ${token} --discovery-token-ca-cert-hash ${ca_hash} --cri-socket=${CRI_SOCKET}"
}

# 生成 Control Plane 节点 Join 命令 (保持不变)
generate_control_plane_join_command() {
    local master_ip_port="$1" token="$2" ca_hash="$3" cert_key="$4"
    echo "kubeadm join ${master_ip_port} --token ${token} --discovery-token-ca-cert-hash ${ca_hash} --control-plane --certificate-key ${cert_key} --cri-socket=${CRI_SOCKET}"
}

###############################################################################
# 主流程
###############################################################################

main_func() {
    echo "[INFO] 开始执行 Kubernetes 集群加入命令生成流程" >&2
    echo "================================================" >&2

    # 1. 获取 Master 节点 IP
    echo "[STEP 1/6] 获取 Master 节点 IP..." >&2
    MASTER_IP=$(get_master_ip)
    MASTER_IP_PORT="${MASTER_IP}:${API_SERVER_PORT}"
    echo "[INFO] Master 节点 API Server 地址: ${MASTER_IP_PORT}" >&2

    # 2. 清理过期的 Token (使用用户函数，尽力而为)
    echo "[STEP 2/6] 清理匹配条件的过期 Token..." >&2
    if ! delete_expired_tokens; then
      echo "[WARNING] 清理过期 Token 时遇到问题 (可能无法获取列表)。" >&2
    fi

    # 3. 查找有效Token (使用用户函数, 捕获其标准输出)
    echo "[STEP 3/6] 查找匹配条件的有效 Token..." >&2
    VALID_TOKEN=$(find_valid_token) # 捕获 find_valid_token 的输出

    # 4. *** 使用原始的、正确的逻辑：检查 $VALID_TOKEN 是否为空 ***
    if [ -z "$VALID_TOKEN" ]; then
        # 如果 find_valid_token 的输出为空字符串，说明没找到
        echo "[INFO] 未找到匹配条件的有效Token或查找失败，正在生成新的Token..." >&2
        VALID_TOKEN=$(generate_new_token) # 捕获新 token
        if [ $? -ne 0 ] || [ -z "$VALID_TOKEN" ]; then # 检查生成是否成功
            echo "ERROR: 最终未能获取或生成有效的 bootstrap token。" >&2
            exit 8
        fi
        echo "[INFO] 新Token生成成功。" >&2
    else
        # 如果 find_valid_token 的输出非空，说明找到了
        echo "[INFO] 使用现有匹配条件的有效Token。" >&2
    fi
    # 此时 $VALID_TOKEN 必然有值 (要么是找到的，要么是新生成的)


    # 5. 获取 CA 证书哈希
    echo "[STEP 4/6] 获取 CA 证书哈希值..." >&2
    CA_HASH=$(get_ca_hash)
    if [ -z "$CA_HASH" ]; then echo "ERROR: 未能获取 CA 哈希值。" >&2; exit 9; fi
    echo "[INFO] CA 证书哈希: $CA_HASH" >&2

    # 6. 上传证书并获取 Certificate Key
    echo "[STEP 5/6] 为控制平面节点准备证书加密密钥..." >&2
    CERTIFICATE_KEY=$(get_certificate_key)
    if [ $? -ne 0 ] || [ -z "$CERTIFICATE_KEY" ]; then echo "ERROR: 未能获取 Certificate Key。" >&2; exit 7; fi
    echo "[INFO] 生成的临时证书加密密钥 (Certificate Key): $CERTIFICATE_KEY" >&2
    echo "[WARN] Certificate Key 有效期为 2 小时! 请在有效期内用于 Master 节点加入。" >&2

    # 7. 生成最终 Join 命令
    echo "[STEP 6/6] 生成加入集群的命令..." >&2
    WORKER_JOIN_CMD=$(generate_worker_join_command "$MASTER_IP_PORT" "$VALID_TOKEN" "$CA_HASH")
    CONTROL_PLANE_JOIN_CMD=$(generate_control_plane_join_command "$MASTER_IP_PORT" "$VALID_TOKEN" "$CA_HASH" "$CERTIFICATE_KEY")

    # --- 输出部分 (保持不变，只输出命令到 stdout) ---
    echo ""
    echo "--------------------------------------------------"
    echo "node加入k8s集群"
    echo "${WORKER_JOIN_CMD}"
    echo ""
    echo "以master角色加入k8s集群"
    echo "${CONTROL_PLANE_JOIN_CMD}"
    echo "--------------------------------------------------"
    # --- 输出结束 ---

    echo "[INFO] 流程执行完毕。" >&2
}

# 执行主函数
main_func

exit 0